﻿#include "../../includes/js/cscriptmanager.h"
#include "../../includes/QsLog/QsLog.h"

#include <QFileInfo>
#include <qDebug>

QScriptValue Q_Debug(QScriptContext *context,QScriptEngine *engine)
{
    QScriptValue a = context->argument(0);

    qDebug()<<a.toString();

    return a;
}

CScriptManager::CScriptManager(QWidget *parent)
    : m_isMonitor(true),
      m_scriptefilechecknum(0)
{
    QObject::connect(&m_FileSystemWatcher,SIGNAL(fileChanged(const QString)),this,SLOT(onProcessfileChanged(const QString)));
    QObject::connect(&m_FileSystemWatcher,SIGNAL(directoryChanged(const QString)),this,SLOT(onProcessdirectoryChanged(const QString)));

    EnableDebugger(DEBUGTYPE_AUTO);
    RegisterNewFunction("qDebug",Q_Debug);
}

CScriptManager::~CScriptManager()
{

}

/**
 * @brief CScriptManager::EnableDebugger 开启调试
 * @param pDebugType 要设置的调试类型
 */
void CScriptManager::EnableDebugger(DebugType pDebugType)
{
    m_scriptdebugger.attachTo(&m_scriptengine);

    switch(pDebugType)
    {
    case DEBUGTYPE_AUTO:
        m_scriptdebugger.setAutoShowStandardWindow(true);
        break;
    case DEBUGTYPE_INTERRUPT:
        m_scriptdebugger.action(QScriptEngineDebugger::InterruptAction)->trigger();
        break;
    default:
        break;
    }
}

/**
 * @brief CScriptManager::RegisterNewFunction 注册一个新的函数
 * @param funcName 要注册的函数的名称
 * @param newfun 要注册的函数
 *
 * @return 返回注册成功后的对象
 */
QScriptValue CScriptManager::RegisterNewFunction(QString funcName,QScriptEngine::FunctionSignature newfun)
{
    if(funcName.isEmpty())
        return QScriptValue();

    QScriptValue scriptFunction = m_scriptengine.newFunction(newfun);
    m_scriptengine.globalObject().setProperty(funcName, scriptFunction);

    m_allregisterobjects[funcName] = scriptFunction;

    return scriptFunction;
}

/**
 * @brief CScriptManager::RegisterNewObject 注册一个新的对象
 * @param objName 要注册的对象的名称
 * @param object 要注册的对象
 *
 * @return 返回注册成功后的对象
 */
QScriptValue CScriptManager::RegisterNewObject(QString objName,QObject *newobject)
{
    if(objName.isEmpty() || newobject == NULL)
        return QScriptValue();

    QScriptValue scriptObject = m_scriptengine.newQObject(newobject/*,QScriptEngine::ScriptOwnership,
                                                          QScriptEngine::ExcludeSuperClassContents*/);
    m_scriptengine.globalObject().setProperty(objName, scriptObject);

    m_allregisterobjects[objName] = scriptObject;

    return scriptObject;
}

/**
 * @brief CScriptManager::RunningScript 开始运行指定的脚本文件
 * @param scriptfile 要运行的脚本文件
 * @param isMonitor 是否要监控这个文件，如果这个文件出现变化，自动重新加载
 *
 * @return 如果脚本运行成功返回真，否则返回假
 */
bool CScriptManager::RunningScript(QString scriptfile,bool isMonitor)
{
    if(scriptfile.isEmpty())
        return false;

    QFileInfo pScriptFile(scriptfile);
    if(!pScriptFile.exists())
    {
        QLOG_INFO()<<"script file:"<<scriptfile<<" is not exists.";
        qDebug()<<"script file:"<<scriptfile<<" is not exists.";
        return false;
    }

    QFile pscriptFile(scriptfile);
    if(!pscriptFile.open(QFile::ReadOnly))
    {
        QLOG_INFO()<<"script file:"<<scriptfile<<" load failed.";
        qDebug()<<"script file:"<<scriptfile<<" load failed.";
        return false;
    }

    //QTextStream pscriptfileout(&pscriptFile);
   // pscriptfileout.setCodec("utf-8");
    QString contents = pscriptFile.readAll();
    pscriptFile.close();

    if(contents.isEmpty())
    {
        QLOG_INFO()<<"script file:"<<scriptfile<<" contents is empty.";
        qDebug()<<"script file:"<<scriptfile<<" contents is empty.";
        return false;
    }

    qint16 scriptefilechecknum = qChecksum(contents.toStdString().c_str(),contents.toStdString().length());

    // 如果脚本文件没有任何改变，就不执行了
    if(scriptefilechecknum == m_scriptefilechecknum)
    {
        QLOG_INFO()<<"script file:"<<scriptfile<<" checknum is same:"<<QString::asprintf("%d",scriptefilechecknum);
        qDebug()<<"script file:"<<scriptfile<<" checknum is same:"<<QString::asprintf("%d",scriptefilechecknum);
        return false;
    }

    QScriptValue result = m_scriptengine.evaluate(contents, scriptfile);

    if (m_scriptengine.hasUncaughtException()) {
        QLOG_ERROR()<<"evaluate:"<<(QString::fromLatin1("%0:%1: %2")
                       .arg(scriptfile)
                       .arg(result.property("lineNumber").toInt32())
                       .arg(result.toString()));
        qDebug()<<"evaluate:"<<(QString::fromLatin1("%0:%1: %2")
                                .arg(scriptfile)
                                .arg(result.property("lineNumber").toInt32())
                                .arg(result.toString()));
        return false;
    }

    m_scriptfile = scriptfile;
    m_isMonitor = isMonitor;
    m_scriptefilechecknum = scriptefilechecknum;

    if(m_isMonitor)
        m_FileSystemWatcher.addPath(scriptfile);

    QLOG_INFO()<<"script file:"<<scriptfile<<" load successed.";
    qDebug()<<"script file:"<<scriptfile<<" load successed.";

    emit ScriptRunningSuccess();

    return true;
}

/**
 * @brief CScriptManager::Reset 重置脚本
 */
void CScriptManager::Reset(void)
{
    if (m_scriptengine.isEvaluating())
        m_scriptengine.abortEvaluation();

    RegisterNewFunction("qDebug",Q_Debug);
}

/**
 * @brief CScriptManager::CreateNewObject 建立一个新的对象
 * @return 返回建立成功的对象
 */
QScriptValue CScriptManager::CreateNewObject(void)
{
    return m_scriptengine.newObject();
}

///得到指定名称的注册对象
QScriptValue CScriptManager::getRegisterObjectByName(QString objName)
{
    if(objName.isEmpty() || m_allregisterobjects.isEmpty())
        return QScriptValue();

    QHash<QString,QScriptValue>::iterator iter = m_allregisterobjects.find(objName);
    if(iter != m_allregisterobjects.end())
        return (*iter);

    return QScriptValue();
}

/**
 * @brief CScriptManager::CallFunction 带参数调用某个方法
 * @param funcName 要调用方法的名称
 * @param params 要调用方法所带的参数
 *
 * @return 如果调用后需要返回的话，就返回调用后的结果
 */
QScriptValue CScriptManager::CallFunction(QString funcName,QScriptValue params)
{
    if(funcName.isEmpty())
        return QScriptValue();

    QScriptValue run_fun = m_scriptengine.globalObject().property(funcName);
    return run_fun.call(QScriptValue(),QScriptValueList() << params);
}

void CScriptManager::onProcessdirectoryChanged(const QString &path)
{

}

void CScriptManager::onProcessfileChanged(const QString &path)
{
    if(m_scriptfile != path || !m_isMonitor)
        return;

    Reset();
    RunningScript(m_scriptfile,m_isMonitor);
}
